﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BizUnit.BizUnitOM;
using BizUnit;
using Microsoft.Practices.ESB.Resolver;

namespace WhiteboardWorks.BizUnitSteps
{
    /// <summary>
    ///The ESBToolkitResolutionValidationStep step applies validation rules in a given ESB Resolution object retrieved from the BizUnit Context.
    ///The ESB Resolution is a structure used by the ESB toolkit to apply endpoint and mapping dynamic resolution.
    /// </summary>
    /// 
    /// <remarks>
    /// The following shows an example of the Xml representation of this test step.
    /// 
    /// <code escaped="true">
    ///	<ESBToolkitResolutionValidationStep assemblyPath="WhiteboardWorks.BizUnitSteps.dll" typeName="WhiteboardWorks.BizUnitSteps.ESBToolkitResolutionValidationStep">
    ///		<FactsContextKey>Facts</FactsContextKey>
    ///		<EndPointWCFAction></EndPointWCFAction>
    ///		<ContextWCFAction></ContextWCFAction>
    ///		<CacheTimeout></CacheTimeout>
    ///		<DocumentSpecName></DocumentSpecName>
    ///		<DocumentSpecStrongName></DocumentSpecStrongName>
    ///		<EndpointConfig></EndpointConfig>
    ///		<EpmRRCorrelationTokenField></EpmRRCorrelationTokenField>
    ///		<FixJaxRpc></FixJaxRpc>
    ///		<InboundTransportLocation></InboundTransportLocation>
    ///		<InboundTransportType></InboundTransportType>
    ///		<InterchangeId></InterchangeId>
    ///		<IsRequestResponse></IsRequestResponse>
    ///		<MessageExchangePattern></MessageExchangePattern>
    ///		<MessageType></MessageType>
    ///		<MethodName></MethodName>
    ///		<OutboundTransportCLSID></OutboundTransportCLSID>
    ///		<ReceiveLocationName></ReceiveLocationName>
    ///		<ReceivePortName></ReceivePortName>
    ///		<TargetNamespace></TargetNamespace>
    ///		<TransformType></TransformType>
    ///		<TransportLocation></TransportLocation>
    ///		<TransportNamespace></TransportNamespace>
    ///		<TransportType></TransportType>
    ///		<WindowUser></WindowUser>
    ///	</ESBToolkitResolutionValidationStep>
    ///	</code>
    ///	
    ///	</remarks>	
    public class ESBToolkitResolutionValidationStep : IValidationStep
    {

        #region IValidationStep Members

        public void ExecuteValidation(System.IO.Stream data, System.Xml.XmlNode validatorConfig, Context context)
        {
            context.LogInfo("ESBToolkitResolutionValidationStep [Start]");

            //Facts to be retrieved from the Context
            object[] facts;

            //Resolution object to be retrieved from the Context
            Resolution esbResolutionFact = null;

            //Key to be used to retrieve the facts from the Context
            string contextKey = context.ReadConfigAsString(validatorConfig, "FactsContextKey", true);

            #region Input Data Validation

            //Check context key to retrieve the facts from Context
            if (String.IsNullOrEmpty(contextKey))
            {
                throw new ApplicationException("FactsContextKey must be provided in order to retrieve the facts from the Context for validation.  Check if the 'FactsContextKey' property is set on the Validation step config, and if you are using other steps that use this context information, make sure that all the key values configured match.");
            }

            //Try to retrieve facts from context with the provided context key
            try
            {
                facts = (object[])context.GetObject(contextKey);
            }
            catch (Exception ex)
            {
                throw new ApplicationException("ESBToolkitResolutionValidationStep could not retrieve the facts from the Context. Make sure they are being stored properly by a previous step. Make sure that the 'FactsContextKey' are properly configured (they should match) in all previous steps: BREExecuteStep and ESBToolkitResolutionContextLoader. Details: " + ex.Message);
            }

            //Try to retrieve ESB Resolution object from facts
            try
            {
                //If ESBToolkitResolutionContextLoader is being properly used, the ESB Resolution object should be on the first array position
                esbResolutionFact = (Resolution)facts[0];
            }
            catch (Exception ex)
            {
                throw new ApplicationException("ESBToolkitResolutionValidationStep could retrieve the ESB Resolution object from the received facts. Please check if ESBToolkitResolutionContextLoader and BREExecute steps are being properly configured. Details: " +  ex.Message);
            }

            #endregion

            StringBuilder outputValidationMessage = new StringBuilder();
            bool isResolutionFactValid = true;

            string expectedAction = context.ReadConfigAsString(validatorConfig, "EndPointWCFAction", true);

            if (!String.IsNullOrEmpty(expectedAction))
            {
                if (esbResolutionFact.Action != expectedAction)
                {
                    isResolutionFactValid = false;
                    outputValidationMessage.AppendLine(String.Format("EndPointWCFAction property is invalid. Expected Value: {0} Returned Value: {1}", expectedAction, esbResolutionFact.Action));
                }
            }


            string expectedActionField = context.ReadConfigAsString(validatorConfig, "ContextWCFAction", true);

            if (!String.IsNullOrEmpty(expectedActionField))
            {
                if (esbResolutionFact.ActionField != expectedActionField)
                {
                    isResolutionFactValid = false;
                    outputValidationMessage.AppendLine(String.Format("ContextWCFAction property is invalid. Expected Value: {0} Returned Value: {1}", expectedActionField, esbResolutionFact.ActionField));
                }
            }


            string expectedCacheTimeout = context.ReadConfigAsString(validatorConfig, "CacheTimeout", true);

            if (!String.IsNullOrEmpty(expectedCacheTimeout))
            {
                if (esbResolutionFact.CacheTimeout != expectedCacheTimeout)
                {
                    isResolutionFactValid = false;
                    outputValidationMessage.AppendLine(String.Format("CacheTimeout property is invalid. Expected Value: {0} Returned Value: {1}", expectedCacheTimeout,  esbResolutionFact.CacheTimeout));
                }
            }

            string expectedDocumentSpecNameField = context.ReadConfigAsString(validatorConfig, "DocumentSpecName", true);

            if (!String.IsNullOrEmpty(expectedDocumentSpecNameField))
            {
                if (esbResolutionFact.DocumentSpecNameField != expectedDocumentSpecNameField)
                {
                    isResolutionFactValid = false;
                    outputValidationMessage.AppendLine(String.Format("DocumentSpecName property is invalid. Expected Value: {0} Returned Value: {1}", expectedDocumentSpecNameField, esbResolutionFact.DocumentSpecNameField));
                }
            }

            string expectedDocumentSpecStrongNameField = context.ReadConfigAsString(validatorConfig, "DocumentSpecStrongName", true);

            if (!String.IsNullOrEmpty(expectedDocumentSpecStrongNameField))
            {
                if (esbResolutionFact.DocumentSpecStrongNameField != expectedDocumentSpecStrongNameField)
                {
                    isResolutionFactValid = false;
                    outputValidationMessage.AppendLine(String.Format("DocumentSpecStrongName property is invalid. Expected Value: {0} Returned Value: {1}", expectedDocumentSpecStrongNameField,  esbResolutionFact.DocumentSpecStrongNameField));
                }
            }


            string expectedEndpointConfig = context.ReadConfigAsString(validatorConfig, "EndpointConfig", true);

            if (!String.IsNullOrEmpty(expectedEndpointConfig))
            {
                if (esbResolutionFact.EndpointConfig != expectedEndpointConfig)
                {
                    isResolutionFactValid = false;
                    outputValidationMessage.AppendLine(String.Format("EndpointConfig property is invalid. Expected Value: {0} Returned Value: {1}", expectedEndpointConfig,  esbResolutionFact.EndpointConfig));
                }
            }


            string expectedEpmRRCorrelationTokenField = context.ReadConfigAsString(validatorConfig, "EpmRRCorrelationToken", true);

            if (!String.IsNullOrEmpty(expectedEpmRRCorrelationTokenField))
            {
                if (esbResolutionFact.EpmRRCorrelationTokenField != expectedEpmRRCorrelationTokenField)
                {
                    isResolutionFactValid = false;
                    outputValidationMessage.AppendLine(String.Format("EpmRRCorrelationToken property is invalid. Expected Value: {0} Returned Value: {1}", expectedEpmRRCorrelationTokenField,  esbResolutionFact.EpmRRCorrelationTokenField));
                }
            }

            string expectedFixJaxRpc = context.ReadConfigAsString(validatorConfig, "FixJaxRpc", true);

            if (!String.IsNullOrEmpty(expectedFixJaxRpc))
            {
                if (esbResolutionFact.FixJaxRpc != Convert.ToBoolean(expectedFixJaxRpc))
                {
                    isResolutionFactValid = false;
                    outputValidationMessage.AppendLine(String.Format("FixJaxRpc property is invalid. Expected Value: {0} Returned Value: {1}", expectedFixJaxRpc,  esbResolutionFact.FixJaxRpc));
                }
            }

            string expectedInboundTransportLocationField = context.ReadConfigAsString(validatorConfig, "InboundTransportLocation", true);

            if (!String.IsNullOrEmpty(expectedInboundTransportLocationField))
            {
                if (esbResolutionFact.InboundTransportLocationField != expectedInboundTransportLocationField)
                {
                    isResolutionFactValid = false;
                    outputValidationMessage.AppendLine(String.Format("InboundTransportLocation property is invalid. Expected Value: {0} Returned Value: {1}", expectedInboundTransportLocationField,  esbResolutionFact.InboundTransportLocationField));
                }
            }

            string expectedInboundTransportTypeField = context.ReadConfigAsString(validatorConfig, "InboundTransportType", true);

            if (!String.IsNullOrEmpty(expectedInboundTransportTypeField))
            {
                if (esbResolutionFact.InboundTransportTypeField != expectedInboundTransportTypeField)
                {
                    isResolutionFactValid = false;
                    outputValidationMessage.AppendLine(String.Format("InboundTransportType property is invalid. Expected Value: {0} Returned Value: {1}", expectedInboundTransportTypeField,  esbResolutionFact.InboundTransportTypeField));
                }
            }

            string expectedInterchangeIdField = context.ReadConfigAsString(validatorConfig, "InterchangeId", true);

            if (!String.IsNullOrEmpty(expectedInterchangeIdField))
            {
                if (esbResolutionFact.InterchangeIdField != expectedInterchangeIdField)
                {
                    isResolutionFactValid = false;
                    outputValidationMessage.AppendLine(String.Format("InterchangeId property is invalid. Expected Value: {0} Returned Value: {1}", expectedInterchangeIdField, esbResolutionFact.InterchangeIdField));
                }
            }

            string expectedIsRequestResponseField = context.ReadConfigAsString(validatorConfig, "IsRequestResponse", true);

            if (!String.IsNullOrEmpty(expectedIsRequestResponseField))
            {
                if (esbResolutionFact.InterchangeIdField != expectedIsRequestResponseField)
                {
                    isResolutionFactValid = false;
                    outputValidationMessage.AppendLine(String.Format("IsRequestResponse property is invalid. Expected Value: {0} Returned Value: {1}", expectedIsRequestResponseField,  esbResolutionFact.IsRequestResponseField));
                }
            }

            string expectedMessageExchangePattern = context.ReadConfigAsString(validatorConfig, "MessageExchangePattern", true);

            if (!String.IsNullOrEmpty(expectedMessageExchangePattern))
            {
                if (esbResolutionFact.MessageExchangePattern != expectedMessageExchangePattern)
                {
                    isResolutionFactValid = false;
                    outputValidationMessage.AppendLine(String.Format("MessageExchangePattern property is invalid. Expected Value: {0} Returned Value: {1}", expectedMessageExchangePattern,  esbResolutionFact.MessageExchangePattern));
                }
            }

            string expectedMessageType = context.ReadConfigAsString(validatorConfig, "MessageType", true);

            if (!String.IsNullOrEmpty(expectedMessageType))
            {
                if (esbResolutionFact.MessageType != expectedMessageType)
                {
                    isResolutionFactValid = false;
                    outputValidationMessage.AppendLine(String.Format("MessageType property is invalid. Expected Value: {0} Returned Value: {1}", expectedMessageType,  esbResolutionFact.MessageType));
                }
            }

            string expectedMethodNameField = context.ReadConfigAsString(validatorConfig, "MethodName", true);

            if (!String.IsNullOrEmpty(expectedMethodNameField))
            {
                if (esbResolutionFact.MethodNameField != expectedMethodNameField)
                {
                    isResolutionFactValid = false;
                    outputValidationMessage.AppendLine(String.Format("MethodName property is invalid. Expected Value: {0} Returned Value: {1}", expectedMethodNameField,  esbResolutionFact.MethodNameField));
                }
            }

            string expectedOutboundTransportCLSID = context.ReadConfigAsString(validatorConfig, "OutboundTransportCLSID", true);

            if (!String.IsNullOrEmpty(expectedOutboundTransportCLSID))
            {
                if (esbResolutionFact.OutboundTransportCLSID != expectedOutboundTransportCLSID)
                {
                    isResolutionFactValid = false;
                    outputValidationMessage.AppendLine(String.Format("OutboundTransportCLSID property is invalid. Expected Value: {0} Returned Value: {1}", expectedOutboundTransportCLSID,  esbResolutionFact.OutboundTransportCLSID));
                }
            }

            string expectedReceiveLocationNameField = context.ReadConfigAsString(validatorConfig, "ReceiveLocationName", true);

            if (!String.IsNullOrEmpty(expectedReceiveLocationNameField))
            {
                if (esbResolutionFact.ReceiveLocationNameField != expectedReceiveLocationNameField)
                {
                    isResolutionFactValid = false;
                    outputValidationMessage.AppendLine(String.Format("ReceiveLocationName property is invalid. Expected Value: {0} Returned Value: {1}", expectedReceiveLocationNameField,  esbResolutionFact.ReceiveLocationNameField));
                }
            }


            string expectedReceivePortNameField = context.ReadConfigAsString(validatorConfig, "ReceivePortName", true);

            if (!String.IsNullOrEmpty(expectedReceivePortNameField))
            {
                if (esbResolutionFact.ReceivePortNameField != expectedReceivePortNameField)
                {
                    isResolutionFactValid = false;
                    outputValidationMessage.AppendLine(String.Format("ReceivePortName property is invalid. Expected Value: {0} Returned Value: {1}", expectedReceivePortNameField,  esbResolutionFact.ReceivePortNameField));
                }
            }


            string expectedSuccess = context.ReadConfigAsString(validatorConfig, "Success", true);

            if (!String.IsNullOrEmpty(expectedSuccess))
            {
                if (esbResolutionFact.Success != Convert.ToBoolean(expectedSuccess))
                {
                    isResolutionFactValid = false;
                    outputValidationMessage.AppendLine(String.Format("Success property is invalid. Expected Value: {0} Returned Value: {1}", expectedSuccess,  esbResolutionFact.Success));
                }
            }

            string expectedTargetNamespace = context.ReadConfigAsString(validatorConfig, "TargetNamespace", true);

            if (!String.IsNullOrEmpty(expectedTargetNamespace))
            {
                if (esbResolutionFact.TargetNamespace != expectedTargetNamespace)
                {
                    isResolutionFactValid = false;
                    outputValidationMessage.AppendLine(String.Format("TargetNamespace property is invalid. Expected Value: {0} Returned Value: {1}", expectedTargetNamespace, esbResolutionFact.TargetNamespace));
                }
            }

            string expectedTransformType = context.ReadConfigAsString(validatorConfig, "TransformType", true);

            if (!String.IsNullOrEmpty(expectedTransformType))
            {
                if (esbResolutionFact.TransformType != expectedTransformType)
                {
                    isResolutionFactValid = false;
                    outputValidationMessage.AppendLine(String.Format("TransformType property is invalid. Expected Value: {0} Returned Value: {1}", expectedTransformType,  esbResolutionFact.TransformType));
                }
            }

            string expectedTransportLocation = context.ReadConfigAsString(validatorConfig, "TransportLocation", true);

            if (!String.IsNullOrEmpty(expectedTransportLocation))
            {
                if (esbResolutionFact.TransportLocation != expectedTransportLocation)
                {
                    isResolutionFactValid = false;
                    outputValidationMessage.AppendLine(String.Format("TransportLocation property is invalid. Expected Value: {0} Returned Value: {1}", expectedTransportLocation,  esbResolutionFact.TransportLocation));
                }
            }

            string expectedTransportNamespace = context.ReadConfigAsString(validatorConfig, "TransportNamespace", true);

            if (!String.IsNullOrEmpty(expectedTransportNamespace))
            {
                if (esbResolutionFact.TransportNamespace != expectedTransportNamespace)
                {
                    isResolutionFactValid = false;
                    outputValidationMessage.AppendLine(String.Format("TransportNamespace property is invalid. Expected Value: {0} Returned Value: {1}", expectedTransportNamespace,  esbResolutionFact.TransportNamespace));
                }
            }

            string expectedTransportType = context.ReadConfigAsString(validatorConfig, "TransportType", true);

            if (!String.IsNullOrEmpty(expectedTransportType))
            {
                if (esbResolutionFact.TransportType != expectedTransportType)
                {
                    isResolutionFactValid = false;
                    outputValidationMessage.AppendLine(String.Format("TransportType property is invalid. Expected Value: {0} Returned Value: {1}", expectedTransportType,  esbResolutionFact.TransportType));
                }
            }

            string expectedWindowUserField = context.ReadConfigAsString(validatorConfig, "WindowUser", true);

            if (!String.IsNullOrEmpty(expectedWindowUserField))
            {
                if (esbResolutionFact.TransportType != expectedWindowUserField)
                {
                    isResolutionFactValid = false;
                    outputValidationMessage.AppendLine(String.Format("WindowUser property is invalid. Expected Value: {0} Returned Value: {1}", expectedWindowUserField,  esbResolutionFact.WindowUserField));
                }
            }

            if(isResolutionFactValid)
            {
                context.LogInfo("ESB Toolkit Resolution Validation Step Status: Success");
            }
            else
            {
                context.LogInfo("ESB Toolkit Resolution Validation Step Status: Error Found.");
                context.LogInfo(outputValidationMessage.ToString());
                throw new ApplicationException("The ESBToolkitResolutionValidationStep found errors with the received ESB Resolution object. Details : " + outputValidationMessage.ToString());
            }

            context.LogInfo("ESBToolkitResolutionValidationStep [End]");
        }

        #endregion
    }
}
